<template>
  <div class="file-browser" ref="browserRef">
    <!-- 工具栏 -->
    <div class="toolbar">
      <div class="path-breadcrumb">
        <span class="breadcrumb-item root" @click="navigateTo('')">
          <SvgIcon name="home" :size="16" />
          <span class="text">根目录</span>
        </span>
        <template v-for="(segment, index) in safePathSegments" :key="index">
          <span class="separator">></span>
          <span 
            class="breadcrumb-item"
            @click="navigateTo(pathSegments.slice(0, index + 1).join('/'))"
          >
            {{ segment }}
          </span>
        </template>
      </div>
      
      <!-- 选中文件信息 -->
      <div class="selection-info" v-if="selectedFiles.size > 0">
        <span class="selection-count">已选中 {{ selectedFiles.size }} 个项目</span>
        <button @click="clearSelection" class="btn-clear" title="取消选择">
          <SvgIcon name="close" :size="14" />
        </button>
      </div>
      
      <div class="toolbar-actions">
        <button @click="refreshFiles" class="btn-icon" title="刷新">
          <SvgIcon name="refresh" :size="16" />
        </button>
        <input 
          type="range" 
          min="80" 
          max="200" 
          v-model.number="gridSize" 
          class="grid-size-slider"
          title="调整图标大小"
        />
      </div>
    </div>
    
    <!-- 文件网格容器 -->
    <div 
      class="file-grid-container"
      ref="fileGridContainer"
      @click="onContainerClick"
      @contextmenu.prevent="onContainerContextMenu"
      @mousedown="onMouseDown"
      @mousemove="onMouseMove"
      @mouseup="onMouseUp"
      @dragenter="onDragEnter"
      @dragover.prevent="onDragOver"
      @dragleave="onDragLeave"
      @drop="onDrop"
    >
      <!-- 文件网格 -->
      <div class="file-grid" :style="gridStyle">
        <FileItem
          v-for="file in files"
          :key="file.path"
          :file="file"
          :isSelected="selectedFiles.has(file.path)"
          :gridSize="gridSize"
          :isRenaming="renamingFile === file.path"
          @select="onFileSelect"
          @open="onFileOpen"
          @contextmenu="onFileContextMenu"
          @longpress="onFileLongPress"
          @dragstart="onFileDragStart"
          @dragend="onFileDragEnd"
          @rename="onFileRename"
          @cancelRename="cancelRename"
        />
      </div>
      
      <!-- 拖拽选择框 -->
      <div
        v-if="isSelecting"
        class="selection-box"
        :style="selectionBoxStyle"
      ></div>
      
      <!-- 拖拽上传提示 -->
      <div v-if="isDragOver" class="drag-overlay">
        <div class="drag-message">
          <div class="drag-icon">📁</div>
          <div class="drag-text">拖拽文件到此处上传</div>
        </div>
      </div>
    </div>
    
    <!-- 右键菜单 -->
    <ContextMenu
      :visible="contextMenu.visible"
      :x="contextMenu.x"
      :y="contextMenu.y"
      :selectedItems="Array.from(selectedFiles.values())"
      @close="closeContextMenu"
      @enterFolder="onEnterFolder"
      @newFolder="showNewFolderDialog"
      @upload="onFilesUpload"
      @refresh="refreshFiles"
      @delete="deleteSelectedFiles"
      @rename="startRename"
    />
    
    <!-- 加载状态 -->
    <div v-if="loading" class="loading-overlay">
      <div class="loading-spinner">加载中...</div>
    </div>
    
    <!-- 上传进度 -->
    <div v-if="isUploading" class="upload-overlay">
      <div class="upload-progress">
        <div class="upload-message">
          <SvgIcon name="upload" :size="24" />
          <span>正在上传文件...</span>
        </div>
        <div class="progress-bar">
          <div class="progress-fill" :style="{ width: uploadProgress + '%' }"></div>
        </div>
        <div class="progress-text">{{ uploadProgress }}%</div>
      </div>
    </div>
    
    <!-- 移动端固定上传按钮 -->
    <div class="mobile-upload-fab">
      <div class="fab-group" :class="{ 'expanded': fabExpanded }">
        <!-- 主按钮 -->
        <button 
          class="fab-main"
          @click="toggleFab($event)"
          :class="{ 'expanded': fabExpanded }"
        >
          <span class="fab-icon">
            <SvgIcon :name="fabExpanded ? 'close' : 'upload'" :size="20" fill="white" />
          </span>
        </button>
        
        <!-- 子按钮 -->
        <div class="fab-actions" v-show="fabExpanded">
          <button class="fab-action" @click="handleMobileUploadFile($event)" title="上传文件">
            <span class="fab-icon">
              <SvgIcon name="upload-file" :size="16" />
            </span>
            <span class="fab-label">文件</span>
          </button>
          <button class="fab-action" @click="handleMobileUploadFolder($event)" title="上传文件夹">
            <span class="fab-icon">
              <SvgIcon name="upload-folder" :size="16" />
            </span>
            <span class="fab-label">文件夹</span>
          </button>
        </div>
      </div>
    </div>
    
    <!-- 隐藏的上传输入框 -->
    <input 
      ref="mobileFileInput" 
      type="file" 
      multiple 
      @change="onMobileFileSelect"
      style="display: none"
    />
    <input 
      ref="mobileFolderInput" 
      type="file" 
      webkitdirectory 
      multiple 
      @change="onMobileFolderSelect"
      style="display: none"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import FileItem from './FileItem.vue'
import ContextMenu from './ContextMenu.vue'
import SvgIcon from './SvgIcon.vue'
import type { FileItem as FileItemType } from '../api/fileService'
import { 
  getFiles, 
  createFolder, 
  uploadFiles, 
  deleteFiles, 
  moveFile,
  downloadFile 
} from '../api/fileService'
import { isValidFileName, validateAndCleanInput, sanitizeDisplayName } from '../utils'

const browserRef = ref<HTMLElement>()
const files = ref<FileItemType[]>([])
const currentPath = ref('')
const selectedFiles = ref<Map<string, FileItemType>>(new Map())
const loading = ref(false)
const uploadProgress = ref(0)
const isUploading = ref(false)
const gridSize = ref(120)
const renamingFile = ref<string | null>(null)

// 拖拽选择相关
const isSelecting = ref(false)
const hasActuallyDragged = ref(false)
const selectionStart = ref({ x: 0, y: 0 })
const selectionEnd = ref({ x: 0, y: 0 })
const fileGridContainer = ref<HTMLElement>()
const isCtrlPressed = ref(false)

// 拖拽上传相关
const isDragOver = ref(false)
const isDraggingInternalFile = ref(false)

// 右键菜单
const contextMenu = reactive({
  visible: false,
  x: 0,
  y: 0
})

// 移动端相关
const fabExpanded = ref(false)
const mobileFileInput = ref<HTMLInputElement | null>(null)
const mobileFolderInput = ref<HTMLInputElement | null>(null)

// 计算属性
const pathSegments = computed(() => {
  return currentPath.value ? currentPath.value.split('/').filter(Boolean) : []
})

// 安全的路径片段显示
const safePathSegments = computed(() => {
  return pathSegments.value.map(segment => sanitizeDisplayName(segment))
})

const gridStyle = computed(() => ({
  gridTemplateColumns: `repeat(auto-fill, minmax(${gridSize.value}px, 1fr))`,
  gap: '16px'
}))

const selectionBoxStyle = computed(() => {
  const left = Math.min(selectionStart.value.x, selectionEnd.value.x)
  const top = Math.min(selectionStart.value.y, selectionEnd.value.y)
  const width = Math.abs(selectionEnd.value.x - selectionStart.value.x)
  const height = Math.abs(selectionEnd.value.y - selectionStart.value.y)
  
  return {
    left: left + 'px',
    top: top + 'px',
    width: width + 'px',
    height: height + 'px'
  }
})

// 生命周期
onMounted(() => {
  loadFiles()
  document.addEventListener('click', onDocumentClick)
  document.addEventListener('keydown', onKeyDown)
})

onUnmounted(() => {
  document.removeEventListener('click', onDocumentClick)
  document.removeEventListener('keydown', onKeyDown)
})

// 文件操作
const loadFiles = async () => {
  try {
    loading.value = true
    const response = await getFiles(currentPath.value)
    if (response.success) {
      files.value = response.data.files
      currentPath.value = response.data.path
    }
  } catch (error) {
    console.error('加载文件失败:', error)
    alert('加载文件失败')
  } finally {
    loading.value = false
  }
}

const refreshFiles = () => {
  loadFiles()
  selectedFiles.value.clear()
}

const navigateTo = (path: string) => {
  currentPath.value = path
  selectedFiles.value.clear()
  loadFiles()
}

const onFileSelect = (file: FileItemType, ctrlKey: boolean) => {
  if (ctrlKey) {
    // Ctrl+点击：切换选择状态
    if (selectedFiles.value.has(file.path)) {
      selectedFiles.value.delete(file.path)
    } else {
      selectedFiles.value.set(file.path, file)
    }
  } else {
    // 单击：选择该文件
    selectedFiles.value.clear()
    selectedFiles.value.set(file.path, file)
  }
}

const onFileOpen = (file: FileItemType) => {
  if (file.type === 'folder') {
    navigateTo(file.path)
  } else {
    // 文件双击下载
    window.open(downloadFile(file.path), '_blank')
  }
}

// 右键菜单
const onContainerContextMenu = (event: MouseEvent) => {
  showContextMenu(event)
}

const onFileContextMenu = (event: MouseEvent, file: FileItemType) => {
  // 如果右键的文件没有被选中，则选中它
  if (!selectedFiles.value.has(file.path)) {
    selectedFiles.value.clear()
    selectedFiles.value.set(file.path, file)
  }
  showContextMenu(event)
}

// 移动端长按支持
const onFileLongPress = (event: TouchEvent, file: FileItemType) => {
  event.preventDefault()
  // 如果长按的文件没有被选中，则选中它
  if (!selectedFiles.value.has(file.path)) {
    selectedFiles.value.clear()
    selectedFiles.value.set(file.path, file)
  }
  
  const touch = event.touches[0]
  showContextMenu({
    clientX: touch.clientX,
    clientY: touch.clientY
  } as MouseEvent)
}

const showContextMenu = (event: MouseEvent) => {
  contextMenu.x = event.clientX
  contextMenu.y = event.clientY
  contextMenu.visible = true
}

const closeContextMenu = () => {
  contextMenu.visible = false
}

const onDocumentClick = (event: Event) => {
  // 检查点击是否在FAB按钮区域内
  const target = event.target as HTMLElement
  const fabContainer = target.closest('.mobile-upload-fab')
  
  // 如果点击不在FAB区域内，则关闭菜单和FAB
  if (!fabContainer) {
    closeContextMenu()
    fabExpanded.value = false
  }
}

// 拖拽选择
const onContainerClick = (event: MouseEvent) => {
  if (event.target === event.currentTarget && !hasActuallyDragged.value) {
    selectedFiles.value.clear()
  }
}

const onMouseDown = (event: MouseEvent) => {
  if (event.button === 0 && event.target === event.currentTarget) {
    isSelecting.value = true
    hasActuallyDragged.value = false
    isCtrlPressed.value = event.ctrlKey || event.metaKey
    
    // 如果没有按住Ctrl键，清空当前选择
    if (!isCtrlPressed.value) {
      selectedFiles.value.clear()
    }
    
    const container = event.currentTarget as HTMLElement
    const rect = container.getBoundingClientRect()
    
    // 计算相对于容器的坐标，并添加滚动偏移
    selectionStart.value = {
      x: event.clientX - rect.left + container.scrollLeft,
      y: event.clientY - rect.top + container.scrollTop
    }
    selectionEnd.value = { ...selectionStart.value }
  }
}

const onMouseMove = (event: MouseEvent) => {
  if (isSelecting.value) {
    const container = fileGridContainer.value
    if (container) {
      const rect = container.getBoundingClientRect()
      
      // 计算相对于容器的坐标，并添加滚动偏移
      const newX = event.clientX - rect.left + container.scrollLeft
      const newY = event.clientY - rect.top + container.scrollTop
      
      selectionEnd.value = { x: newX, y: newY }
      
      // 检测是否实际移动了鼠标（超过一定距离才算拖拽）
      const deltaX = Math.abs(newX - selectionStart.value.x)
      const deltaY = Math.abs(newY - selectionStart.value.y)
      if (deltaX > 5 || deltaY > 5) {
        hasActuallyDragged.value = true
      }
      
      // 框选文件逻辑
      updateSelection()
    }
  }
}

const onMouseUp = () => {
  isSelecting.value = false
  // 延迟重置拖拽状态，避免与点击事件冲突
  setTimeout(() => {
    hasActuallyDragged.value = false
  }, 10)
}

const updateSelection = () => {
  if (!fileGridContainer.value) return
  
  const selectionLeft = Math.min(selectionStart.value.x, selectionEnd.value.x)
  const selectionTop = Math.min(selectionStart.value.y, selectionEnd.value.y)
  const selectionRight = Math.max(selectionStart.value.x, selectionEnd.value.x)
  const selectionBottom = Math.max(selectionStart.value.y, selectionEnd.value.y)
  
  // 获取所有文件项元素
  const fileItems = fileGridContainer.value.querySelectorAll('.file-item')
  
  // 如果按住Ctrl，在现有选择基础上添加，否则重新选择
  const newSelectedFiles = isCtrlPressed.value 
    ? new Map<string, FileItemType>(selectedFiles.value)
    : new Map<string, FileItemType>()
  
  fileItems.forEach((element, index) => {
    const rect = element.getBoundingClientRect()
    const containerRect = fileGridContainer.value!.getBoundingClientRect()
    
    // 计算文件项相对于容器的位置
    const itemLeft = rect.left - containerRect.left + fileGridContainer.value!.scrollLeft
    const itemTop = rect.top - containerRect.top + fileGridContainer.value!.scrollTop
    const itemRight = itemLeft + rect.width
    const itemBottom = itemTop + rect.height
    
    // 检查是否与选择框重叠
    const isOverlapping = !(
      itemRight < selectionLeft ||
      itemLeft > selectionRight ||
      itemBottom < selectionTop ||
      itemTop > selectionBottom
    )
    
    if (isOverlapping && files.value[index]) {
      const file = files.value[index]
      newSelectedFiles.set(file.path, file)
    }
  })
  
  selectedFiles.value = newSelectedFiles
}

// 拖拽上传
const onDragEnter = (event: DragEvent) => {
  event.preventDefault()
  // 只有在拖拽外部文件时才显示上传提示
  if (!isDraggingInternalFile.value) {
    isDragOver.value = true
  }
}

const onDragOver = (event: DragEvent) => {
  event.preventDefault()
  // 保持上传提示状态
}

const onDragLeave = (event: DragEvent) => {
  event.preventDefault()
  // 检查是否真的离开了容器（避免在子元素间移动时误触发）
  const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()
  if (
    event.clientX < rect.left ||
    event.clientX > rect.right ||
    event.clientY < rect.top ||
    event.clientY > rect.bottom
  ) {
    isDragOver.value = false
  }
}

const onDrop = (event: DragEvent) => {
  event.preventDefault()
  isDragOver.value = false
  
  // 只处理外部文件拖拽
  if (!isDraggingInternalFile.value) {
    const dt = event.dataTransfer
    if (dt?.files && dt.files.length > 0) {
      const fileList = Array.from(dt.files)
      onFilesUpload(fileList)
    }
  }
}

// 文件操作
const showNewFolderDialog = () => {
  const name = prompt('请输入文件夹名称:')
  if (name) {
    // 验证并清理用户输入
    const cleanedName = validateAndCleanInput(name, 255)
    if (cleanedName && isValidFileName(cleanedName)) {
      createNewFolder(cleanedName)
    } else {
      alert('文件夹名称包含非法字符或为空')
    }
  }
}

const createNewFolder = async (name: string) => {
  try {
    // 再次验证清理输入
    const safeName = validateAndCleanInput(name, 255)
    if (!safeName) {
      alert('文件夹名称无效')
      return
    }
    
    const response = await createFolder(safeName, currentPath.value)
    if (response.success) {
      refreshFiles()
    } else {
      alert(response.message || '创建文件夹失败')
    }
  } catch (error) {
    console.error('创建文件夹失败:', error)
    alert('创建文件夹失败')
  }
}

const onFilesUpload = async (fileList: File[]) => {
  try {
    isUploading.value = true
    uploadProgress.value = 0
    
    const response = await uploadFiles(fileList, currentPath.value, (progress) => {
      uploadProgress.value = progress
    })
    
    if (response.success) {
      refreshFiles()
    } else {
      alert(response.message || '上传失败')
    }
  } catch (error) {
    console.error('上传失败:', error)
    alert('上传失败')
  } finally {
    isUploading.value = false
    uploadProgress.value = 0
  }
}

const deleteSelectedFiles = async () => {
  const selectedItems = Array.from(selectedFiles.value.values())
  if (selectedItems.length === 0) return
  
  let confirmMessage = ''
  if (selectedItems.length === 1) {
    // 使用安全的文件名显示
    const safeName = sanitizeDisplayName(selectedItems[0].name)
    confirmMessage = `确定要删除 "${safeName}" 吗？`
  } else {
    // 对所有文件名进行安全处理
    const safeNames = selectedItems.map(f => sanitizeDisplayName(f.name)).join('\n')
    confirmMessage = `确定要删除这 ${selectedItems.length} 个项目吗？\n\n${safeNames}`
  }
  
  if (confirm(confirmMessage)) {
    try {
      const paths = selectedItems.map(f => f.path)
      const response = await deleteFiles(paths)
      if (response.success) {
        refreshFiles()
      } else {
        alert(response.message || '删除失败')
      }
    } catch (error) {
      console.error('删除失败:', error)
      alert('删除失败')
    }
  }
}

const clearSelection = () => {
  selectedFiles.value.clear()
}

const startRename = () => {
  const selectedItems = Array.from(selectedFiles.value.values())
  if (selectedItems.length === 1) {
    renamingFile.value = selectedItems[0].path
  }
}

const onFileRename = async (oldName: string, newName: string) => {
  try {
    if (!renamingFile.value) {
      console.error('重命名失败: 没有正在重命名的文件')
      alert('重命名失败: 没有正在重命名的文件')
      return
    }
    
    const oldPath = renamingFile.value
    // 更精确的路径替换：只替换文件名部分
    const pathParts = oldPath.split('/')
    const fileName = pathParts[pathParts.length - 1]
    if (fileName !== oldName) {
      console.error('重命名失败: 文件名不匹配', { fileName, oldName })
      alert('重命名失败: 文件名不匹配')
      return
    }
    pathParts[pathParts.length - 1] = newName
    const newPath = pathParts.join('/')
    
    const response = await moveFile(oldPath, newPath)
    if (response.success) {
      refreshFiles()
    } else {
      alert(response.message || '重命名失败')
    }
  } catch (error) {
    console.error('重命名失败:', error)
    alert('重命名失败')
  } finally {
    renamingFile.value = null
  }
}

const cancelRename = () => {
  renamingFile.value = null
}

// 文件拖拽
const onFileDragStart = (_file: FileItemType) => {
  isDraggingInternalFile.value = true
}

const onFileDragEnd = () => {
  isDraggingInternalFile.value = false
}

// 键盘快捷键
const onKeyDown = (event: KeyboardEvent) => {
  if (event.key === 'Delete' && selectedFiles.value.size > 0) {
    deleteSelectedFiles()
  } else if (event.key === 'F5') {
    event.preventDefault()
    refreshFiles()
  } else if (event.key === 'Escape') {
    selectedFiles.value.clear()
    closeContextMenu()
    if (renamingFile.value) {
      cancelRename()
    }
  }
}

// 移动端相关
const toggleFab = (event?: Event) => {
  event?.stopPropagation()
  fabExpanded.value = !fabExpanded.value
}

const handleMobileUploadFile = (event?: Event) => {
  event?.stopPropagation()
  mobileFileInput.value?.click()
  fabExpanded.value = false
}

const handleMobileUploadFolder = (event?: Event) => {
  event?.stopPropagation()
  mobileFolderInput.value?.click()
  fabExpanded.value = false
}

const onMobileFileSelect = (event: Event) => {
  const target = event.target as HTMLInputElement
  if (target.files) {
    const files = Array.from(target.files)
    onFilesUpload(files)
    target.value = '' // 清空输入框
  }
}

const onMobileFolderSelect = (event: Event) => {
  const target = event.target as HTMLInputElement
  if (target.files) {
    const files = Array.from(target.files)
    onFilesUpload(files)
    target.value = '' // 清空输入框
  }
}

const onEnterFolder = (folder: FileItemType) => {
  navigateTo(folder.path)
}
</script>

<style lang="less" scoped>
.file-browser {
  height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: #fafafa;
  position: relative;
  
  .toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 20px;
    background: #ffffff;
    border-bottom: 1px solid #e5e5e5;
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    
    .path-breadcrumb {
      display: flex;
      align-items: center;
      font-size: 14px;
      font-weight: 400;
      
      .breadcrumb-item {
        cursor: pointer;
        padding: 6px 10px;
        border-radius: 6px;
        transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
        color: #424242;
        display: flex;
        align-items: center;
        gap: 6px;
        
        &:hover {
          background-color: #f5f5f5;
          color: #1a1a1a;
        }
        
        &.root {
          font-weight: 500;
          color: #2563eb;
          
          &:hover {
            background-color: #eff6ff;
          }
        }
        
        .text {
          white-space: nowrap;
        }
      }
      
      .separator {
        margin: 0 4px;
        color: #9ca3af;
        font-size: 12px;
      }
    }
    
    // 选中文件信息
    .selection-info {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 6px 12px;
      background: linear-gradient(135deg, #eff6ff, #f0f9ff);
      border: 1px solid #cbd5e1;
      border-radius: 8px;
      animation: slideIn 0.2s ease-out;
      
      .selection-count {
        font-size: 13px;
        font-weight: 500;
        color: #1e40af;
      }
      
      .btn-clear {
        background: none;
        border: none;
        cursor: pointer;
        padding: 4px;
        border-radius: 4px;
        color: #6b7280;
        transition: all 0.15s ease;
        display: flex;
        align-items: center;
        justify-content: center;
        
        &:hover {
          background: rgba(59, 130, 246, 0.1);
          color: #3b82f6;
          transform: scale(1.1);
        }
      }
    }
    
    @keyframes slideIn {
      from {
        opacity: 0;
        transform: translateX(-10px);
      }
      to {
        opacity: 1;
        transform: translateX(0);
      }
    }
    
    .toolbar-actions {
      display: flex;
      align-items: center;
      gap: 12px;
      
      .btn-icon {
        background: none;
        border: none;
        font-size: 16px;
        cursor: pointer;
        padding: 8px;
        border-radius: 6px;
        transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
        color: #6b7280;
        
        &:hover {
          background-color: #f3f4f6;
          color: #374151;
          transform: scale(1.05);
        }
        
        &:active {
          transform: scale(0.98);
        }
      }
      
      .grid-size-slider {
        width: 100px;
        height: 4px;
        border-radius: 2px;
        background: #e5e7eb;
        outline: none;
        appearance: none;
        cursor: pointer;
        
        &::-webkit-slider-thumb {
          appearance: none;
          width: 16px;
          height: 16px;
          border-radius: 50%;
          background: #2563eb;
          cursor: pointer;
          transition: all 0.15s ease;
          
          &:hover {
            transform: scale(1.1);
            box-shadow: 0 0 0 8px rgba(37, 99, 235, 0.1);
          }
        }
        
        &::-moz-range-thumb {
          width: 16px;
          height: 16px;
          border-radius: 50%;
          background: #2563eb;
          cursor: pointer;
          border: none;
        }
      }
    }
  }
  
  .file-grid-container {
    flex: 1;
    overflow: auto;
    position: relative;
    padding: 20px;
    background: #fafafa;
    
    .file-grid {
      display: grid;
      align-items: start;
    }
    
    .selection-box {
      position: absolute;
      border: 1px solid #3b82f6;
      background: linear-gradient(135deg, rgba(59, 130, 246, 0.06), rgba(59, 130, 246, 0.03));
      backdrop-filter: blur(2px);
      -webkit-backdrop-filter: blur(2px);
      pointer-events: none;
      z-index: 10;
      border-radius: 4px;
      box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.2), 
                  0 4px 12px rgba(59, 130, 246, 0.1);
    }
    
    .drag-overlay {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: linear-gradient(135deg, rgba(59, 130, 246, 0.08), rgba(99, 102, 241, 0.06));
      border: 2px dashed #6366f1;
      border-radius: 12px;
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 100;
      backdrop-filter: blur(8px);
      -webkit-backdrop-filter: blur(8px);
      
      .drag-message {
        text-align: center;
        color: #4f46e5;
        
        .drag-icon {
          font-size: 48px;
          margin-bottom: 16px;
          opacity: 0.8;
        }
        
        .drag-text {
          font-size: 18px;
          font-weight: 500;
          letter-spacing: -0.025em;
        }
      }
    }
  }
  
  .loading-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(255, 255, 255, 0.85);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    
    .loading-spinner {
      font-size: 16px;
      font-weight: 500;
      color: #6b7280;
      display: flex;
      align-items: center;
      gap: 12px;
      
      &::before {
        content: '';
        width: 20px;
        height: 20px;
        border: 2px solid #e5e7eb;
        border-top: 2px solid #3b82f6;
        border-radius: 50%;
        animation: spin 1s linear infinite;
      }
    }
    
    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }
  }
  
  .upload-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(255, 255, 255, 0.8);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    
    .upload-progress {
      background: #ffffff;
      padding: 24px;
      border-radius: 16px;
      box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08), 
                  0 8px 24px rgba(0, 0, 0, 0.12);
      min-width: 300px;
      max-width: 400px;
      
      .upload-message {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 12px;
        color: #4f46e5;
        font-size: 16px;
        font-weight: 500;
        margin-bottom: 20px;
        
        svg {
          animation: uploadPulse 2s ease-in-out infinite;
        }
      }
      
      .progress-bar {
        width: 100%;
        height: 8px;
        background: #f3f4f6;
        border-radius: 4px;
        overflow: hidden;
        margin-bottom: 12px;
        
        .progress-fill {
          height: 100%;
          background: linear-gradient(90deg, #3b82f6, #1d4ed8);
          border-radius: 4px;
          transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
          position: relative;
          
          &::after {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: linear-gradient(
              90deg,
              transparent,
              rgba(255, 255, 255, 0.3),
              transparent
            );
            animation: progressShimmer 1.5s ease-in-out infinite;
          }
        }
      }
      
      .progress-text {
        text-align: center;
        color: #6b7280;
        font-size: 14px;
        font-weight: 500;
        margin: 0;
      }
    }
    
    @keyframes uploadPulse {
      0%, 100% {
        transform: scale(1);
        opacity: 1;
      }
      50% {
        transform: scale(1.1);
        opacity: 0.8;
      }
    }
    
    @keyframes progressShimmer {
      0% {
        transform: translateX(-100%);
      }
      100% {
        transform: translateX(100%);
      }
    }
  }
  
  .mobile-upload-fab {
    position: fixed;
    bottom: 24px;
    right: 24px;
    z-index: 1000;
    display: none; // 默认隐藏，仅在移动端显示
    
    .fab-group {
      display: flex;
      flex-direction: column;
      align-items: center;
      
      .fab-main {
        width: 56px;
        height: 56px;
        border-radius: 50%;
        background: linear-gradient(135deg, #3b82f6, #2563eb);
        border: none;
        color: white;
        cursor: pointer;
        box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3), 
                    0 8px 20px rgba(59, 130, 246, 0.15);
        transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
        display: flex;
        align-items: center;
        justify-content: center;
        margin-bottom: 8px;
        user-select: none;
        -webkit-user-select: none;
        -webkit-tap-highlight-color: transparent;
        
        &:hover {
          transform: scale(1.05);
          box-shadow: 0 6px 16px rgba(59, 130, 246, 0.4), 
                      0 12px 24px rgba(59, 130, 246, 0.2);
        }
        
        &:active {
          transform: scale(0.95);
        }
        
        .fab-icon {
          display: flex;
          align-items: center;
          justify-content: center;
          width: 24px;
          height: 24px;
          transition: transform 0.15s ease;
          pointer-events: none;
        }
        
        &.expanded .fab-icon {
          transform: rotate(45deg);
        }
      }
      
      .fab-actions {
        display: flex;
        flex-direction: column;
        gap: 8px;
        opacity: 0;
        transform: translateY(10px);
        pointer-events: none;
        transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
        
        .fab-action {
          width: 48px;
          height: 48px;
          border-radius: 50%;
          background: rgba(255, 255, 255, 0.95);
          backdrop-filter: blur(10px);
          -webkit-backdrop-filter: blur(10px);
          border: 1px solid rgba(229, 231, 235, 0.8);
          color: #374151;
          cursor: pointer;
          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
          transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
          display: flex;
          align-items: center;
          justify-content: center;
          position: relative;
          user-select: none;
          -webkit-user-select: none;
          -webkit-tap-highlight-color: transparent;
          
          &:hover {
            background: white;
            transform: scale(1.05);
            box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
          }
          
          &:active {
            transform: scale(0.95);
          }
          
          .fab-icon {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 20px;
            height: 20px;
            pointer-events: none;
          }
          
          .fab-label {
            position: absolute;
            right: 56px;
            top: 50%;
            transform: translateY(-50%);
            background: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 4px 8px;
            border-radius: 4px;
            font-size: 12px;
            white-space: nowrap;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.15s ease;
          }
          
          &:hover .fab-label {
            opacity: 1;
          }
        }
      }
      
      &.expanded .fab-actions {
        opacity: 1;
        transform: translateY(0);
        pointer-events: all;
      }
    }
  }
}

// 响应式设计
@media (max-width: 768px) {
  .file-browser {
    .toolbar {
      padding: 12px 16px;
      flex-direction: column;
      gap: 8px;
      align-items: stretch;
      
      .path-breadcrumb {
        font-size: 13px;
        order: 1;
      }
      
      .selection-info {
        order: 2;
        justify-content: center;
        padding: 8px 12px;
        
        .selection-count {
          font-size: 14px;
        }
      }
      
      .toolbar-actions {
        order: 3;
        justify-content: center;
        gap: 8px;
        
        .grid-size-slider {
          width: 80px;
        }
      }
    }
    
    .file-grid-container {
      padding: 16px;
      padding-bottom: 100px; // 为浮动按钮留出空间
    }
    
    // 显示移动端上传按钮
    .mobile-upload-fab {
      display: block;
    }
    
    // 移动端上传进度条样式调整
    .upload-overlay {
      padding: 16px;
      
      .upload-progress {
        min-width: auto;
        max-width: 100%;
        padding: 20px;
        border-radius: 12px;
        
        .upload-message {
          font-size: 15px;
          gap: 10px;
          margin-bottom: 16px;
        }
        
        .progress-bar {
          height: 6px;
          margin-bottom: 10px;
        }
        
        .progress-text {
          font-size: 13px;
        }
      }
    }
  }
}

// 平板和小屏幕也显示浮动按钮
@media (max-width: 1024px) and (pointer: coarse) {
  .file-browser .mobile-upload-fab {
    display: block;
  }
}
</style> 